home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / networking / pgpuam / sources / pgpservermemory.cp < prev    next >
Encoding:
Text File  |  2000-06-23  |  12.9 KB  |  406 lines

  1. //    PGPServerMemory.cp -  AppleShare IP memory management
  2. // 
  3. // Apple Macintosh Developer Technical Support
  4. // Written by:  Vinne Moscaritolo
  5. //
  6. //  Copyright (work in progress)  Apple Computer, Inc All rights reserved.
  7. //
  8. // You may incorporate this sample code into your applications without
  9. // restriction, though the sample code has been provided "AS IS" and the
  10. // responsibility for its operation is 100% yours.  However, what you are
  11. // not permitted to do is to redistribute the source as "DSC Sample Code"
  12. // after having made changes. If you're going to re-distribute the source,
  13. // we require that you make it clear in the source that the code was
  14. // descended from Apple Sample Code, but that you've made changes.
  15. // 
  16.  
  17. #include <OpenTransport.h> 
  18.  
  19. #define FIX_ASLM
  20. #include <LibraryManager.h>
  21.  
  22.   
  23. #define PGP_MACINTOSH 1
  24.  
  25. #include "pgpErrors.h"
  26. #include "pgpKeys.h"
  27. #include "pgpMemoryMgr.h"
  28. #include "pgpUtilities.h"
  29. #include "pgpFeatures.h"
  30. #include "pgpHash.h"
  31. #include "pgpPublicKey.h"
  32. #include "TPGPException.h"
  33. #include "TMacException.h"
  34.  
  35. #include "PGPServerMemory.h"
  36.  
  37. #define  OTAssert( _Msg_, _cond_)     ThrowMsgIfNot( _cond_, _Msg_)
  38.  
  39.     
  40. // ---------------------------------------------------------------------------
  41. #pragma mark Local Globals?
  42. // ---------------------------------------------------------------------------
  43. static     Boolean                     gVirtualMemoryisEnabled = false;
  44. static    PGPNewContextStruct         gContextInfo;
  45. static    PGPNewMemoryMgrStruct        gMemMgrInfo;
  46.  
  47. static     unsigned long                gMemBytesUsed = 0;
  48. static     unsigned long                gMemSecureBytesUsed = 0;
  49.  
  50.  
  51. // ---------------------------------------------------------------------------
  52. #pragma mark Local Prototypes
  53. // ---------------------------------------------------------------------------
  54.  
  55. static void *  MemoryAllocationProc ( PGPMemoryMgrRef mgr,
  56.                                         PGPUserValue userValue,
  57.                                         PGPSize requestSize, 
  58.                                         PGPMemoryMgrFlags flags );
  59.  
  60. static    PGPError MemoryReallocationProc ( PGPMemoryMgrRef mgr,
  61.                                           PGPUserValue userValue,
  62.                                           void **allocation, 
  63.                                           PGPSize newAllocationSize,
  64.                                           PGPMemoryMgrFlags flags, 
  65.                                           PGPSize existingSize );
  66.  
  67. static    PGPError MemoryDeallocationProc ( PGPMemoryMgrRef mgr,
  68.                                           PGPUserValue userValue,
  69.                                           void *allocation, 
  70.                                           PGPSize allocationSize );
  71.  
  72.  
  73. static     void*      MemorySecureAllocationProc ( PGPMemoryMgrRef mgr,
  74.                                               PGPUserValue userValue,
  75.                                               PGPSize requestSize, 
  76.                                               PGPMemoryMgrFlags flags,
  77.                                                  PGPBoolean *isNonPageable );
  78.                         
  79. static PGPError     MemorySecureDeallocationProc ( PGPMemoryMgrRef mgr,
  80.                                                 PGPUserValue userValue,
  81.                                                 void *allocation, 
  82.                                                 PGPSize allocationSize,
  83.                                                 PGPBoolean    wasLocked );
  84.                                                 
  85. static OSStatus InitOpenTransportWithMemoryLimit(void);
  86.  
  87. #pragma mark -
  88.  
  89. // ---------------------------------------------------------------------------
  90. static void *  MemoryAllocationProc ( PGPMemoryMgrRef mgr,
  91.                                         PGPUserValue userValue,
  92.                                         PGPSize requestSize, 
  93.                                         PGPMemoryMgrFlags flags )
  94. // ---------------------------------------------------------------------------
  95. //
  96. {
  97. //    DebugStr("\p Allocation");    
  98.  
  99.     void* p =  OTAllocMem(requestSize) ;
  100.     
  101.     if(p) gMemBytesUsed+= requestSize;
  102.     
  103.      if(!p) DebugStr("\p Allocation Failed");    
  104.  
  105.      return p;
  106.      
  107.  }
  108.  
  109. // ---------------------------------------------------------------------------
  110. static    PGPError MemoryReallocationProc ( PGPMemoryMgrRef mgr,
  111.                                           PGPUserValue userValue,
  112.                                           void **allocation, 
  113.                                           PGPSize newAllocationSize,
  114.                                           PGPMemoryMgrFlags flags, 
  115.                                           PGPSize existingSize )
  116. // ---------------------------------------------------------------------------
  117. //
  118. {
  119.     void* p;
  120. //    DebugStr("\p Reallocation");    
  121.  
  122.     p =  OTAllocMem(newAllocationSize);
  123.      if(!p) DebugStr("\p Reallocation Failed");    
  124.     if(!p) 
  125.     {
  126.           OTFreeMem(p);
  127.         return(kPGPError_OutOfMemory);
  128.     }
  129.     else
  130.     {
  131.          gMemBytesUsed+= (newAllocationSize - existingSize);
  132.         
  133.         OTMemcpy(p,  *allocation, existingSize);
  134.           OTFreeMem( *allocation );
  135.         *allocation = p;
  136.     }
  137.     
  138.       return noErr;
  139. }
  140.                                           
  141.                             
  142.  
  143. // ---------------------------------------------------------------------------
  144. static    PGPError MemoryDeallocationProc ( PGPMemoryMgrRef mgr,
  145.                                           PGPUserValue userValue,
  146.                                           void *allocation, 
  147.                                           PGPSize allocationSize )
  148. // ---------------------------------------------------------------------------
  149. //
  150. {
  151.  
  152. //    DebugStr("\p Deallocation");    
  153.  
  154.     gMemBytesUsed-=allocationSize;
  155.     
  156.      OTFreeMem( allocation );
  157.     return noErr;
  158. }
  159.  
  160.  
  161.  
  162. // ---------------------------------------------------------------------------
  163. static     void*      MemorySecureAllocationProc ( PGPMemoryMgrRef mgr,
  164.                                               PGPUserValue userValue,
  165.                                               PGPSize requestSize, 
  166.                                               PGPMemoryMgrFlags flags,
  167.                                                  PGPBoolean *isNonPageable )
  168. // ---------------------------------------------------------------------------
  169. //
  170. {
  171.     void* p;
  172.     
  173.  //    DebugStr("\p  Secure Allocation");    
  174.  
  175.     p =  OTAllocMem(requestSize);
  176.       if(!p) DebugStr("\p Secure Allocation Failed");    
  177.     
  178.     if(p)
  179.     {
  180.          if(gVirtualMemoryisEnabled)    HoldMemory(p, requestSize);
  181.          gMemSecureBytesUsed+=requestSize;
  182.     }
  183.      return(p);
  184. }
  185.  
  186.                         
  187. // ---------------------------------------------------------------------------
  188. static PGPError     MemorySecureDeallocationProc ( PGPMemoryMgrRef mgr,
  189.                                                 PGPUserValue userValue,
  190.                                                 void *allocation, 
  191.                                                 PGPSize allocationSize,
  192.                                                 PGPBoolean    wasLocked )
  193. // ---------------------------------------------------------------------------
  194. //
  195. {
  196.  
  197. //     DebugStr("\p  Secure Deallocation");    
  198.     
  199.     OTMemzero(allocation, allocationSize);
  200.      if(gVirtualMemoryisEnabled) UnholdMemory(allocation, allocationSize);
  201.      OTFreeMem( allocation );
  202.     gMemSecureBytesUsed-=allocationSize;
  203.     
  204.     return noErr;
  205. }
  206.  
  207. #pragma mark -
  208.  
  209. // ---------------------------------------------------------------------------
  210. OSStatus InitializeServerMemory(  PGPMemoryMgrRef *memMgr )
  211. // ---------------------------------------------------------------------------
  212. //
  213. {
  214.     OSStatus err;
  215.     
  216.     long response = 0;
  217.  
  218. // Is virtual memory enabled?
  219.     Gestalt(gestaltVMAttr, &response);
  220.     gVirtualMemoryisEnabled = (response & (1UL << gestaltVMPresent)) != 0;
  221.         
  222. // Setup opentransport for memory usage
  223.     err = InitOpenTransportWithMemoryLimit();
  224.     if(err != noErr) return err;
  225.  
  226. // preallocate memory into heap.
  227.      OTFreeMem(OTAllocMem( 64 * 1024));
  228.  
  229. // setup custom PGP memory manager structure
  230.       gMemMgrInfo.sizeofStruct =   sizeof( PGPNewMemoryMgrStruct );
  231.     gMemMgrInfo.allocProc              =     MemoryAllocationProc;
  232.     gMemMgrInfo.reallocProc          =     MemoryReallocationProc;
  233.     gMemMgrInfo.deallocProc          =     MemoryDeallocationProc;
  234.     gMemMgrInfo.secureAllocProc      =     MemorySecureAllocationProc;
  235.     gMemMgrInfo.secureDeallocProc      =     MemorySecureDeallocationProc;
  236.     gMemMgrInfo.customValue          =     nil;
  237.     gMemMgrInfo.reserved  =     nil;
  238.     gMemMgrInfo.pad[0]  =     nil;
  239.     gMemMgrInfo.pad[1]  =     nil;
  240.     gMemMgrInfo.pad[2]  =     nil;
  241.     gMemMgrInfo.pad[3]  =     nil;
  242.     gMemMgrInfo.pad[4]  =     nil;
  243.     gMemMgrInfo.pad[5]  =     nil;
  244.     gMemMgrInfo.pad[6]  =     nil;
  245.     gMemMgrInfo.pad[7]  =     nil;
  246.  
  247.     err = PGPNewMemoryMgrCustom( &gMemMgrInfo, memMgr);
  248.     
  249.     return err;
  250. }
  251.  
  252.  
  253. // ---------------------------------------------------------------------------
  254. void FinalizeServerMemory( PGPMemoryMgrRef memMgr )
  255. // ---------------------------------------------------------------------------
  256. //
  257. {
  258.     PGPFreeMemoryMgr(memMgr);
  259.  
  260.     CloseOpenTransport();
  261.     CleanupLibraryManager();
  262. }
  263.  
  264. #pragma mark -
  265.  
  266. // from Quinn's StreamLogWatcher.c
  267. // 
  268. // InitOpenTransportWithMemoryLimit Big Picture
  269. // --------------------------------------------
  270. //
  271. // The LogEngine uses the OT memory allocation routines
  272. // (OTAllocMem, OTFreeMem) to allocate space for log entries in
  273. // the notifier.  This memory comes from an ASLM memory pool
  274. // that OT creates for us when we call InitOpenTransport.  However,
  275. // this pool has some bad characteristics:
  276. //
  277. //     1.    The pool starts off very small, and only grows when we allocate
  278. //         memory from it.  As we do all our allocation from our notifier
  279. //        (which is interrupt time with respect to the system Memory Manager)
  280. //        the pool can't grow immediately.  So the pool will often run
  281. //        be full (ie OTAllocMem will return nil) even though the application
  282. //        has plenty of memory.  The pool will later grow, but we've already
  283. //        dropped the log entry on the floor.
  284. //
  285. //    2.    Because the pool starts off small and grows by pieces, we get
  286. //        an extremely fragmented pool.  While this works, its definitely
  287. //        sub-optimal.
  288. //
  289. //    3.    If we're being hammered by strlog (ie people are calling strlog a
  290. //        lot), the pool will keep growing and there's nothing to stop
  291. //        the pool consuming our entire application heap.  When it does so,
  292. //        various toolbox routines (eg QuickDraw) fail ungracefully, ie
  293. //        SysError(25).
  294. //
  295. // There are a number of steps in my solution to this.  The first step
  296. // is to call InitLibraryManager myself.  This allows me to specify
  297. // the size of the pool. InitOpenTransport notices that I have inited ASLM
  298. // myself and doesn't do it itself.  Thus OTAllocMem gets its memory from
  299. // whatever pool ASLM created.  This gets around problems 1 and 2.
  300. //
  301. // The second step is to create a subsidiary zone within my application heap
  302. // and specify that ASLM should create its pool in that zone (by supplying
  303. // kCurrentZone to InitLibraryManager).  Thus the pool can grow up to the
  304. // point where the memory in the subsidiary zone is exhausted.  At that point,
  305. // the pool will no longer grow.  So the pool will not steal memory from
  306. // the main application heap.  This gets around problem 3.
  307. //
  308. // There are a number of other ways I could have achieved the same results.
  309. // The ASLM memory manager is very flexible.  For example, I could have removed
  310. // OT's TPoolNotifier from the pool, which would prevent the pool from growing.
  311. // However, this solution does not require me to use any ASLM C++ stuff,
  312. // which makes the code more compiler independent.
  313.  
  314. enum {
  315.     kBytesReservedForToolboxInApplicationZone = 100L * 1024L,
  316.         // This value represents the minimum number of contiguous
  317.         // bytes that should remain in the application heap after
  318.         // we've created the subsidiary zone.
  319.         
  320.     kBytesReservedForASLMInSubsidaryzone = 2048,
  321.         // This value represents the number of bytes in the subsidiary
  322.         // zone we should leave lying around for general purpose ASLM
  323.         // use.  The remaining bytes in the subsidiary zone are
  324.         // dedicated to the ASLM memory pool, ie are passed as the pool
  325.         // size to InitLibraryManager.
  326.         
  327.     kMinimumBytesForUsInSubsidiaryZone = 10 * 1024
  328.         // This value represents the minimum pool size we pass to
  329.         // InitLibraryManager.  If we can't create a pool of at least
  330.         // this size, the application doesn't start up.
  331. };
  332.  
  333.  
  334. static OSStatus InitOpenTransportWithMemoryLimit(void)
  335.     // See above for an explanation of the big picture here.
  336. {
  337.     OSStatus err;
  338.     SInt32 junkTotalFree;
  339.     SInt32 contigFree;
  340.     SInt32 zoneSize;
  341.     Ptr gSubsidiaryZone;
  342.     THz oldZone;
  343.  
  344.     // Debugger();
  345.     
  346.     // First call the system Memory Manager to determine the largest
  347.     // contiguous block in the heap.
  348.     
  349.     PurgeSpace(&junkTotalFree, &contigFree);
  350.     
  351.     // If it's too small for our toolbox needs, bail out.
  352.     
  353.     err = noErr;
  354.     if (contigFree < kBytesReservedForToolboxInApplicationZone) {
  355.         err = memFullErr;
  356.     }
  357.     
  358.     // Now calculate the size of the zone we're going to create.
  359.     // It's the size of the largest contiguous block, minus
  360.     // the size of we reserve for toolbox needs, rounded to the nearest KB.
  361.     // If the zone size isn't big enough enough to hold our minimum
  362.     // pool size and the amount we reserve for ASLM, bail out.
  363.     
  364.     if (err == noErr) {
  365.         zoneSize = contigFree - kBytesReservedForToolboxInApplicationZone;
  366.         zoneSize = zoneSize & ~0x003FF;
  367.         if (zoneSize < (kBytesReservedForASLMInSubsidaryzone + kMinimumBytesForUsInSubsidiaryZone)) {
  368.             err = memFullErr;
  369.         }
  370.     }
  371.     
  372.     // Allocate the memory for our zone and create a zone in that
  373.     // block.  Then init ASLM, telling it to create a pool that
  374.     // takes up the entire zone (minus the ASLM overhead factor)
  375.     // in the current zone, ie the zone we just created.  Finally,
  376.     // initialise OT.  OT will see that we've inited ASLM and use
  377.     // the pool that ASLM created (in the zone we created) for
  378.     // satisfying OTAllocMem requests.
  379.     
  380.     if (err == noErr) {
  381.         gSubsidiaryZone = NewPtr(zoneSize);
  382.         OTAssert("InitOpenTransportWithMemoryLimit: Couldn't get the memory but preflight says its there", gSubsidiaryZone != nil);
  383.         OTAssert("InitOpenTransportWithMemoryLimit: Just being paranoid", MemError() == noErr);
  384.  
  385.         oldZone = GetZone();
  386.  
  387.         InitZone(nil, 16, gSubsidiaryZone + zoneSize, gSubsidiaryZone);
  388.         OTAssert("InitOpenTransportWithMemoryLimit: InitZone failed", MemError() == noErr);
  389.  
  390.         // InitZone sets the current zone to the newly created zone,
  391.         // so I don't have to do it myself.
  392.                 
  393.         err = InitLibraryManager(zoneSize - kBytesReservedForASLMInSubsidaryzone, kCurrentZone, kNormalMemory);
  394.         if (err == noErr) {
  395.             err = InitOpenTransport();
  396.             if (err != noErr) {
  397.                 CleanupLibraryManager();
  398.             }
  399.         }
  400.         
  401.         SetZone(oldZone);
  402.     }
  403.  
  404.       return err;
  405. }
  406.